package cn.larry.common.utils.wx;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import cn.larry.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * This is created,
 * but not necessarily updated by me.
 * Therefore, AUTHOR is useless.
 * 2023/12/22 11:20
 * 【企业微信考勤打卡】
 *
 * @Version 1.0
 */
@Slf4j
@Component
public class QywxCheckinTool {

    // 获取打卡日报数据
    public static final String GET_CHECKIN_DAYDATA = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckin_daydata?access_token={token}";
    // 获取打卡月报数据
    public static final String GETCHECKIN_MONTHDATA = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckin_monthdata?access_token={token}";

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 获取打卡记录信息【默认查询昨天的】
     *
     * @param startStr   开始时间（yyyy-MM-dd HH:mm:ss），含等于
     * @param endStr     结束时间（yyyy-MM-dd HH:mm:ss），不含等于
     * @param userIdList 企业微信用户ID
     * @param userIdList token
     */
    public JSONArray syncCheckinByDay(String startStr, String endStr, List<String> userIdList,
                                      String token) {
        Date start;
        Date end;
        if (StringUtils.isBlank(startStr) || StringUtils.isBlank(endStr)) {
            // 查询昨天的
            LocalDateTime localDateTime = LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0);
            start = DateUtils.toDate(localDateTime);
            end = DateUtils.toDate(localDateTime.plusDays(1));
        } else {
            start = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", startStr);
            end = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", endStr);
        }

        return inBatches(start, end, userIdList, token);
    }

    /**
     * 月打卡记录数据
     *
     * @param startStr
     * @param endStr
     * @param userIdList
     * @param token
     * @return
     */
    public JSONArray syncCheckinByMonth(String startStr, String endStr, List<String> userIdList,
                                        String token) {
        Date start;
        Date end;
        if (StringUtils.isBlank(startStr) || StringUtils.isBlank(endStr)) {
            // 查询昨天的
            LocalDateTime localDateTime = LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0);
            start = DateUtils.toDate(localDateTime);
            end = DateUtils.toDate(localDateTime.plusDays(1));
        } else {
            start = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", startStr);
            end = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", endStr);
        }

        int staMonthNun = start.getMonth() + 1;// 查询的月份
        return getCheckinMonth(staMonthNun, userIdList, token);
    }

    /**
     * 获取打卡记录信息
     * 大于100，分批获取
     */
    public JSONArray inBatches(Date start, Date end,
                               List<String> userIdList,
                               String token) {
        if (userIdList == null || userIdList.size() < 1) {
            return null;
        }
        JSONArray checkinData = new JSONArray();
        if (userIdList.size() <= 100) {
            // 小于等于100，一次性获取
            checkinData = getCheckinData(start, end, userIdList, token);
        } else {
            // 按每100个一组分割
            Integer MAX_SEND = 100;
            // 计算切分次数
            int limit = (userIdList.size() + MAX_SEND - 1) / MAX_SEND;
            List<List<String>> splitList = Stream.iterate(0, n -> n + 1).limit(limit).parallel().map(a -> userIdList.stream().skip(a * MAX_SEND).limit(MAX_SEND).parallel().collect(Collectors.toList())).collect(Collectors.toList());
            for (List<String> subList : splitList) {
                checkinData.add(getCheckinData(start, end, subList, token));
            }
        }
        return checkinData;
    }

    /**
     * 请求微信获取：指定员工指定日期的日打卡记录数据【默认查询昨天的】
     *
     * @param startDate  开始时间，含等于
     * @param endDate    结束时间，不含等于
     * @param qywxIdList 微信用户ID的List列表
     * @param token      应用token
     */
    @Transactional(rollbackFor = Exception.class)
    public JSONArray getCheckinData(Date startDate, Date endDate,
                                    @NotNull List<String> qywxIdList,
                                    String token) {

        if (startDate == null || endDate == null) {
            // 查询昨天的
            LocalDateTime localDateTime = LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0);
            startDate = DateUtils.toDate(localDateTime);// 昨天0点
            endDate = DateUtils.toDate(localDateTime.plusDays(1));// 今天0点
        }
        /*
         * 获取打卡日报数据
         * 参考：https://developer.work.weixin.qq.com/document/path/93374
         */
        // 组请求渠道的报文
        Map<String, Object> body = new HashMap<>();
        body.put("starttime", startDate.getTime() / 1000);// 0点Unix时间戳
        body.put("endtime", endDate.getTime() / 1000);// 0点Unix时间戳
        body.put("useridlist", qywxIdList);
        Map<String, String> uriVariables = new HashMap<>();
        uriVariables.put("token", token);
        // 请求渠道
        JSONObject result = restTemplate.postForObject(GET_CHECKIN_DAYDATA, JSONObject.toJSONString(body), JSONObject.class, uriVariables);
        if (0 != result.getIntValue("errcode")) {
            throw new RuntimeException("send wechat message error : " + result.get("errmsg"));
        }
        return result.getJSONArray("datas");
    }

    /**
     * * 请求微信获取：指定员工指定日期的月打卡记录数据【默认查询本月的】
     *
     * @param nowYearStaMonthNun 当前年月份（1～12）
     * @param qywxIdList
     * @param token
     */
    public JSONArray getCheckinMonth(int nowYearStaMonthNun,
                                     @NotNull List<String> qywxIdList,
                                     @NotNull String token) {
        Date startDate = null;
        Date endDate = null;
        if (nowYearStaMonthNun >= 1 && nowYearStaMonthNun < 13) {
            LocalDateTime startLocalDate = LocalDateTime.now().withMonth(nowYearStaMonthNun).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
            startDate = DateUtils.toDate(startLocalDate);// 1日0点
            endDate = DateUtils.toDate(startLocalDate.plusMonths(1));// 下个月1日0点
        } else {// 查询本月的
            startDate = DateUtils.toDate(LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0));// 本月1日0点
            endDate = DateUtils.toDate(LocalDateTime.now().with(TemporalAdjusters.lastDayOfMonth()).withHour(0).withMinute(0).withSecond(0).plusDays(1));// 下月1日0点
        }
        return getCheckinMonth(startDate, endDate, qywxIdList, token);
    }

    /**
     * 请求微信获取：指定员工指定日期的月打卡记录数据【默认查询本月的】
     *
     * @param startDate  开始时间，含等于
     * @param endDate    结束时间，不含等于
     * @param qywxIdList 微信用户ID的List列表
     * @param token
     */
    public JSONArray getCheckinMonth(Date startDate, Date endDate,
                                     @NotNull List<String> qywxIdList,
                                     @NotNull String token) {
        if (startDate == null || endDate == null) {
            // 查询本月的
            startDate = DateUtils.toDate(LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0));// 本月1日0点
            endDate = DateUtils.toDate(LocalDateTime.now().with(TemporalAdjusters.lastDayOfMonth()).withHour(0).withMinute(0).withSecond(0).plusDays(1));// 下月1日0点
        }
        /*
         * 获取打卡月报数据
         * 参考：https://developer.work.weixin.qq.com/document/path/93387
         */
        // 组请求渠道的报文
        Map<String, Object> body = new HashMap<>();
        body.put("starttime", startDate.getTime() / 1000);// 0点Unix时间戳
        body.put("endtime", endDate.getTime() / 1000);// 0点Unix时间戳
        body.put("useridlist", qywxIdList);
        Map<String, String> uriVariables = new HashMap<>();
        uriVariables.put("token", token);
        // 请求渠道
        JSONObject result = restTemplate.postForObject(GETCHECKIN_MONTHDATA, JSON.toJSONString(body), JSONObject.class, uriVariables);
        if (0 != result.getIntValue("errcode")) {
            throw new RuntimeException("send wechat message error : " + result.get("errmsg"));
        }
        // 处理应答
        return result.getJSONArray("datas");
    }

}
